using System.Net;
using System.Net.Sockets;
using Pinwheel.Kernel;

namespace Pinwheel.Service
{
    public partial class GatewayBase : IGatewayService
    {
        public virtual void OnConnected(ISocketSession session)
        {
            var endPoint = session.ReceiveEventArgs.RemoteEndPoint as IPEndPoint;
            Assert.Check(endPoint != null, $"[{Alias}]OnConnected RemoteEndPoint{session.ReceiveEventArgs.RemoteEndPoint} is not IPEndPoint");
            
            var pid = PID.Create();
            bool result = Global.SocketSession2PidMap.TryAdd(session, pid);
            Assert.Check(result, $"[[{Alias}]OnConnected add exists unauthorized connection: {pid}");
            if (!result) Log.Info($"[[{Alias}]OnConnected add exists unauthorized connection: {pid}");
            
            result = result ? Global.ClientConnectionMap.TryAdd(pid, new Connection(ServiceManager, session)) : result;
            Assert.Check(result, $"[[{Alias}]OnConnected add exists unauthorized connection: {pid}");
            if (!result) Log.Info($"[[{Alias}]OnConnected add exists unauthorized connection: {pid}");
        }

        public virtual void OnConnectFailed(ISocketSession session)
        {
        }

        public virtual void OnReceive(ISocketSession session)
        {
            byte[] buffer = null;
            var size = session.Received.Pop(ref buffer, 0);
            if (size > 0)
            {
                if (Global.SocketSession2PidMap.TryGetValue(session, out var pid))
                {
                    if (Global.ClientConnectionMap.TryGetValue(pid, out var conn))
                    {
                        var netPacket = conn.Decode(buffer);
                        Forward(conn, ref pid, ref netPacket);
                        return;
                    }
                }
                Assert.Check(false, $"[{Alias}]Drop unknown connection message: {size} bytes");
                Log.Info($"[{Alias}]Drop unknown connection message: {size} bytes");
            }
        }

        public virtual void OnError(ISocketSession session, SocketError error)
        {
            OnClose(session);
        }
        
        public virtual void OnClose(ISocketSession session)
        {
            var endPoint = session.ReceiveEventArgs.RemoteEndPoint as IPEndPoint;
            Assert.Check(endPoint != null, $"[GatewayBase]OnClose RemoteEndPoint{session.ReceiveEventArgs.RemoteEndPoint} is not IPEndPoint");
            
            bool result = Global.SocketSession2PidMap.TryRemove(session, out var pid);
            Assert.Check(result, $"[Gateway]OnClose has no unauthorized connection: {pid}");
            if (!result) Log.Info($"[Gateway]OnClose has no unauthorized connection: {pid}");
            
            result = Global.ClientConnectionMap.TryRemove(pid, out _);
            Assert.Check(result, $"[Gateway]OnClose has no unauthorized connection: {pid}");
            if (!result) Log.Info($"[Gateway]OnClose has no unauthorized connection: {pid}");
        }
        
        protected void Forward(IConnection conn, ref PID source, ref NetPacket packet)
        {
            if (PID.Invalid != conn.Agent)
            {
                // Log.Info($"[{Node}][{Alias}]Forward session:{packet.Session} type:{packet.Type} from:{source} to:{conn.Agent}");
                Send(source, conn.Agent, ref packet);
            }
            else if (PID.Invalid != m_Watchdog)
            {
                // Log.Info($"[{Node}][{Alias}]Forward session:{packet.Session} type:{packet.Type} from:{source} to:{m_Watchdog}");
                Send(source, m_Watchdog, ref packet);
            }
        }
    }
}